#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "route2.h"
#include <main.h>
#include "route_sync.h"

/* 
 * Define unsigned 32-bit integer type for consistent data representation
 * This type definition ensures platform-independent integer handling
 * Used for metric calculations and network address manipulations
 */
typedef unsigned int uint32_t; 

/* 
 * Define constants for parsing route command output columns
 * These constants represent the positional indices in route -n output
 * GATEWAY_ITEM: Position of gateway address in route table output
 * METRIC_ITEM: Position of route metric value in output
 * IFACE_ITEM: Position of interface name in route table output
 */
#define GATEWAY_ITEM 1
#define METRIC_ITEM 4
#define IFACE_ITEM 7

/* 
 * Define network constants for default route handling
 * DEFAULT_DESTINATION: IP address representing default route (0.0.0.0)
 * DIRECTORY: Systemd network configuration directory path
 * BUFFER_SIZE: Standard buffer size for file operations and string handling
 * PPP_FILE_NAME_PERFIX: Prefix for PPP interface configuration files
 */
#define DEFAULT_DESTINATION "0.0.0.0"
#define DIRECTORY "/etc/systemd/network/"
#define BUFFER_SIZE 256
#define PPP_FILE_NAME_PERFIX "10-"

/* 
 * Retrieve all default routes from system routing table
 * This function executes route -n command and parses default gateway entries
 * Uses grep to filter only default routes (0.0.0.0 destinations)
 * Populates RouteList structure with gateway, interface and metric information
 * Handles memory allocation and cleanup for temporary string operations
 * 
 * @return RouteList Structure containing all default routes found in system
 */
RouteList get_default_routes() {
    /* File pointer for command execution pipe */
    FILE *fp;
    /* Buffer for reading command output line by line */
    char line[256];
    /* Structure to store collected route information */
    RouteList route_list;
    /* Initialize route count to zero */
    route_list.count = 0;
    
    /* Execute route command with grep filter for default routes */
    fp = popen("route -n | grep '^0\.0\.0\.0'", "r");
    /* Validate command execution was successful */
    if (fp == NULL) {
        perror("popen");
        exit(EXIT_FAILURE);
    }

    /* Process each line of command output */
    while (fgets(line, sizeof(line), fp) != NULL) {
        /* Check if line contains default route and capacity available */
        if (strcspn(line, "0.0.0.0") == 0 && route_list.count < MAX_ROUTES) {
            /* Buffers for gateway and interface name extraction */
            char gateway[MAX_GATEWAY_LEN] = "";
            char iface[MAX_IFACE_LEN] = "";
            
            /* Duplicate string for tokenization without modifying original */
            char *temp_str = strdup(line); // Copy string for modification
            /* Token pointer for string splitting */
            char *token;
            /* Array to store split string components */
            char *result[10]; // Assume maximum of 10 split strings
            int index = 0;

            // Use strtok to split string by spaces
            /* Begin tokenization of route table line */
            token = strtok(temp_str, " ");
            /* Continue tokenization until all components processed */
            while (token != NULL) {
                result[index++] = token; // Store split string in array
                token = strtok(NULL, " ");
            }
      
            /* Process interface name to remove newline character */
            for (int i = 0; result[IFACE_ITEM][i] != '\0'; ++i) {
                // If newline found, replace with null terminator
                if (result[IFACE_ITEM][i] == '\n') {
                    result[IFACE_ITEM][i] = '\0';
                    break;  // Exit loop after replacement
                }
            }

            //printf("gateway = %s iface = %s metric = %d \n",result[GATEWAY_ITEM],result[IFACE_ITEM],strtoul(&result[METRIC_ITEM],NULL,10));
            /* Copy gateway address to route structure */
            strncpy(route_list.routes[route_list.count].gateway, result[GATEWAY_ITEM], MAX_GATEWAY_LEN);
            /* Copy interface name to route structure */
            strncpy(route_list.routes[route_list.count].iface, result[IFACE_ITEM], MAX_IFACE_LEN);
            /* Convert metric string to unsigned long and store */
            route_list.routes[route_list.count].metric = strtoul(&result[METRIC_ITEM],NULL,10);
            /* Increment route counter for next entry */
            route_list.count++;

            /* Free duplicated string memory */
            free(temp_str); // Release copied string memory
        }
    }

    /* Close command execution pipe */
    pclose(fp);
    /* Return populated route list structure */
    return route_list;
}



/* 
 * Check if specific route configuration exists in network interfaces file
 * This function scans the network configuration file for matching route entries
 * Compares destination, mask and device parameters against existing configurations
 * Used to prevent duplicate route entries in system configuration
 * 
 * @param dev Network interface device name to check
 * @param dst Destination network address to verify
 * @param mask Network mask for route specification
 * @return int Returns 1 if route exists, 0 if not found
 */
int route_exists(const char *dev, const char *dst, const char *mask) {
    /* Open interfaces file for reading */
    FILE *file = fopen(INTERFACES_FILE, "r");
    /* Validate file opened successfully */
    if (!file) {
        perror("Unable to open interfaces file");
        return 0;
    }

    /* Buffer for reading file lines */
    char line[256];
    /* Scan each line in configuration file */
    while (fgets(line, sizeof(line), file)) {
        /* Check if line contains all three route identifiers */
        if (strstr(line, dst) && strstr(line, mask) && strstr(line, dev)) {
            /* Close file and return found status */
            fclose(file);
            return 1;
        }
    }

    /* Close file after complete scan */
    fclose(file);
    /* Return not found status */
    return 0;
}

/* 
 * Prioritize routing metrics for specific network interface
 * This function adjusts route metrics to give priority to specified device
 * Sets metric to 0 for target device and increases metrics for other interfaces
 * Ensures the specified device becomes the preferred default route
 * 
 * @param routes Pointer to RouteList structure containing all routes
 * @param dev Target network interface device to prioritize
 * @return int Returns 1 if prioritization successful, 0 if device not found
 */
int prioritize_route(RouteList *routes, const char *dev) {
    /* Flag to track if target device was found */
    int found = 0;
    /* Return value indicating operation success */
    int ret = 0;
    // Check if any route has metric 0
    /* Iterate through all routes in the list */
    for (int i = 0; i < routes->count; i++) {
        /* Check for routes with highest priority (metric 0) */
        if (routes->routes[i].metric == 0) {
            // If the device is found with metric 0, set found flag
            /* Check if current route matches target device */
            if (strcmp(routes->routes[i].iface, dev) == 0) {
                /* Set flag indicating device already has priority */
                found = 1;
                /* Set return value to success */
                ret = 1;
            } else {
                // Increase the metric of others with metric 0
                /* Demote other high-priority routes by increasing metric */
                routes->routes[i].metric += 1;
            }
        }
    }
    // If the device was not found with metric 0, set it to 0
    /* Handle case where target device doesn't have highest priority */
    if (!found) {
        /* Search for target device in route list */
        for (int i = 0; i < routes->count; i++) {
            /* Check if current route matches target device */
            if (strcmp(routes->routes[i].iface, dev) == 0) {
                /* Set metric to 0 for highest priority */
                routes->routes[i].metric = 0;
                /* Set return value to success */
                ret = 1;
                /* Exit loop after finding device */
                break;
            }
        }
    }

    /* Check if operation was unsuccessful */
    if(1 != ret){
        printf("dev doesn't have a default route!\n");
    }
    /* Return operation status */
    return ret;
}

/* 
 * Display IP route commands for all routes in list
 * This function generates and prints ip route add commands for debugging
 * Shows the exact commands that would be executed to recreate routing table
 * Useful for verification and manual route configuration
 * 
 * @param routes Pointer to RouteList structure containing routes to display
 */
void print_ip_route_commands(const RouteList *routes) {
    /* Iterate through all routes in the list */
    for (int i = 0; i < routes->count; i++) {
        /* Print ip route command for current route */
        printf("ip route add default via %s dev %s metric %d\n",
               routes->routes[i].gateway,
               routes->routes[i].iface,
               routes->routes[i].metric);
    }
}

/* 
 * Apply all routes from RouteList to system routing table
 * This function clears existing default routes and adds new ones from list
 * Uses system commands to modify routing table configuration
 * Provides error handling for individual route addition failures
 * 
 * @param routes Pointer to RouteList structure containing routes to add
 * @return int Returns 1 if all routes added successfully, 0 on any failure
 */
int add_routes(const RouteList *routes) {
    /* Initialize return value to success */
    int ret = 1;
    /* Clear all existing default routes before adding new ones */
    if(clear_all_default_routes()){
        /* Iterate through all routes in the list */
        for (int i = 0; i < routes->count; i++) {
            //  printf("ip route add default via %s dev %s metric %d\n",
            //         routes->routes[i].gateway,
            //         routes->routes[i].iface,
            //         routes->routes[i].metric);
            /* Add individual route to system */
            if(!add_default_route(routes->routes[i].iface, routes->routes[i].gateway, routes->routes[i].metric)){
                /* Set return value to failure if any route addition fails */
                ret = 0;
            }
        }
    }
    else{
        /* Set return value to failure if route clearing fails */
        ret = 0;
    }
    /* Return overall operation status */
    return ret;
}

/* 
 * Set default route priority for specific network device
 * This function configures the routing table to prioritize specified interface
 * Retrieves current routes, adjusts metrics, and applies new configuration
 * Used to control traffic flow through specific network interfaces
 * 
 * @param dev Network interface device name to set as priority route
 * @return int Returns 0 on success, -1 on failure
 */
int set_default_route(const char *dev){
    
    /* Initialize return value to error */
    int ret = -1;
    /* Retrieve current default routes from system */
    RouteList routes = get_default_routes();
    /* Check if any default routes exist */
    if (routes.count == 0){
        //add default routes
        printf("No default gateway existed.\n");
        return ret;
    }

    /* Prioritize specified device in route list */
    if(prioritize_route(&routes, dev)){
        /* Apply modified route configuration to system */
        if(add_routes(&routes)){
            /* Set return value to success */
            ret = 0;
        }
    }
    /* Return operation status */
    return ret;
}

/* 
 * Add static route configuration to network interface file
 * This function creates persistent route entries in systemd network files
 * Configures destination-based routing with specified prefix length
 * Ensures routes persist across system reboots and network restarts
 * 
 * @param dev Network interface device name for route
 * @param dst Destination network address for route
 * @param prefix_length_str CIDR prefix length as string
 * @return int Returns 0 on success, -1 on failure
 */
int  add_route_to_file(const char *dev, const char *dst, const char *prefix_length_str) {

    /* Buffer for network configuration file path */
    char file_path[256];
    
    //Build a network profile path
    /* Construct full path to network configuration file */
    get_network_config_file_path(file_path, sizeof(file_path), dev);


    // Check whether the route already exists
    /* Verify route doesn't already exist in configuration */
    if (check_route_exists(file_path, dst, prefix_length_str)) {
        printf("Route already exists: Address=%s/%s on %s\n", dst, prefix_length_str, dev);
        return 0;
    }

    //Open your device's .network profile
    /* Open network configuration file in append mode */
    FILE *file = fopen(file_path, "a");
    /* Validate file opened successfully */
    if (file == NULL) {
        perror("Failed to open network configuration file");
        return -1;
    }

    // Build [Route] section content
    /* Buffer for constructing route configuration entry */
    char route_entry[256];
    // build "dev".network section
    /* Format route configuration with destination and scope */
    snprintf(route_entry, sizeof(route_entry), "\n[Route]\nDestination=%s/%s\nScope=link\n",dst, prefix_length_str);

    //Appends the content to the end of the file
    /* Write route configuration to file */
    if (fputs(route_entry, file) == EOF) {
        perror("Failed to write to network configuration file");
        fclose(file);
        return -1;
    }
 
    // close file
    /* Close configuration file after writing */
    fclose(file);

    printf("Route added to %s: Address=%s/%s\n", dev, dst, prefix_length_str);

    return 0;


}

/* 
 * Add default route configuration to network interface file
 * This function creates persistent default gateway entries in systemd files
 * Configures gateway-based default routing with metric priority
 * Triggers route synchronization after configuration update
 * 
 * @param dev Network interface device name for default route
 * @param gateway Gateway IP address for default route
 * @param metric Route metric value for priority determination
 * @return int Returns 0 on success, -1 on failure
 */
int  add_default_route_to_file(const char *dev, const char *gateway, const int metric) {

    /* Buffer for network configuration file path */
    char file_path[256];
    
    //Build a network profile path
    /* Construct full path to network configuration file */
    get_network_config_file_path(file_path, sizeof(file_path), dev);

    /* Remove existing default route for this gateway */
    Delete_default_route(file_path,gateway);

    //Open your device's .network profile
    /* Open network configuration file in append mode */
    FILE *file = fopen(file_path, "a");
    /* Validate file opened successfully */
    if (file == NULL) {
        perror("Failed to open network configuration file");
        return -1;
    }

    // Build [Route] section content
    /* Buffer for constructing default route configuration */
    char route_entry[256];
    // build "dev".network section
    /* Format default route configuration with gateway and metric */
    snprintf(route_entry, sizeof(route_entry), "[Route]\nGateway=%s\nMetric=%d\n",gateway, metric);

    //Appends the content to the end of the file
    /* Write default route configuration to file */
    if (fputs(route_entry, file) == EOF) {
        perror("Failed to write to network configuration file");
        fclose(file);
        return -1;
    }
 
    // close file
    /* Close configuration file after writing */
    fclose(file);

    //printf("Route added to %s:Gateway=%s Metric=%d\n", dev, gateway, metric);

    /* Initialize route table structure for synchronization */
    RouteTable table = {0};
    /* Synchronize routing configuration with system */
    wwan_route_sync(&table);

    return 0;


}

/* 
 * Delete static route configuration from network interface file
 * This function removes persistent route entries from systemd network files
 * Parses configuration file to locate and remove specific route sections
 * Maintains file integrity by preserving other configuration sections
 * 
 * @param dev Network interface device name for route deletion
 * @param dst Destination network address to remove
 * @param prefix_length_str CIDR prefix length as string for route identification
 */
void delete_route_from_file(const char *dev, const char *dst, const char *prefix_length_str) {
	/* Buffer for network configuration file path */
	char file_path[256];
   /* Buffer for constructing destination match string */
   char destination_match[256];
   
    // Get network configuration file path
    /* Construct full path to network configuration file */
    get_network_config_file_path(file_path, sizeof(file_path), dev);


    // Open file in read-only mode
    /* Open configuration file for reading */
    FILE *file = fopen(file_path, "r");
    /* Validate file opened successfully */
    if (!file) {
        perror("delete_route_from_file fopen");
        return;
    }
    
    // Print debug information
    //printf("打开文件: %s\n", file_path);

    // Buffer for reading file lines
    char line[1024];
    // Dynamic array for storing file content
    // Dynamically allocate array for line storage
    char **lines = NULL;
    int line_count = 0;

    // Read each file line and store in lines array
    /* Process each line in configuration file */
    while (fgets(line, sizeof(line), file)) {
        // Remove trailing newline character
        line[strcspn(line, "\n")] = 0;
        
        // Dynamically expand array to store current line
        /* Reallocate memory for additional line */
        char **tmp = realloc(lines, (line_count + 1) * sizeof(char*));
        /* Validate memory allocation success */
        if (!tmp) { // Check reallocation success
            perror("realloc");
            /* Clean up previously allocated memory */
            for (int j = 0; j < line_count; j++) {
                free(lines[j]); // Free previous line memory
            }
            free(lines); // Free line array memory
            fclose(file);
            return;
        }
        lines = tmp; // Update pointer
        lines[line_count] = strdup(line); // Copy string
        /* Validate string duplication success */
        if (!lines[line_count]) { // Check strdup success
            perror("realloc");
            /* Clean up previously allocated memory */
            for (int j = 0; j < line_count; j++) {
                free(lines[j]); // Free previous line memory
            }
            free(lines); // Free line array memory
            fclose(file);
            return;
        }
        line_count++;
    }
    fclose(file); // Close file

    // Create new content excluding specified section
    /* Open file for writing new configuration */
    FILE *new_file = fopen(file_path, "w");
    /* Validate file opened successfully */
    if (!new_file) {
        perror("file_path fopen");
        // Free memory
        for (int i = 0; i < line_count; i++) {
            free(lines[i]);
        }
        free(lines);
        return;
    }

    int skip_section = 0; // Flag indicating whether to skip section
	
	// Build matching route line
	/* Construct destination match string for route identification */
	snprintf(destination_match, sizeof(destination_match), "Destination=%s/%s", dst, prefix_length_str); // Construct "Destination=192.168.10.0/24" line

    /* Process each line for section filtering */
    for (int i = 0; i < line_count; i++) {
        // Check if specific section matches
        /* Identify route section to delete */
        if (i < line_count - 2 && 
            strcmp(lines[i], "[Route]") == 0 && 
            strstr(lines[i + 1], destination_match) != NULL && 
            strstr(lines[i + 2], "Scope=link") != NULL) {
            skip_section = 1; // Activate skip flag
        }

        /* Handle section skipping logic */
        if (skip_section) {
            // Continue skipping section logic
            // printf("跳过段落: %s\n", lines[i]);
            // printf("跳过段落2: %s\n", lines[i+2]);
            i+=3;
        } else {
            // Write other lines to file
            fputs(lines[i], new_file);
            fputc('\n', new_file); // Add newline
        }
        skip_section = 0;
    }

    fclose(new_file); // Close new file
    // Free memory
    for (int i = 0; i < line_count; i++) {
        free(lines[i]); // Free line memory
    }
    free(lines); // Free line array memory

    // Check if route was completely deleted
    /* Verify route removal was successful */
    if (check_route_exists(file_path, dst, prefix_length_str) == 1) {
        printf("Failed to delete a route from the interfaces file\n");
    }
    else{
        printf("Route deleted from %s: Destination=%s/%s succeed\n", dev, dst, prefix_length_str);
    }

}


/* 
 * Convert dotted decimal subnet mask to CIDR prefix length
 * This function parses traditional subnet mask format to prefix notation
 * Validates mask format and ensures it represents contiguous bits
 * Used for compatibility between different route configuration methods
 * 
 * @param mask Dotted decimal subnet mask string (e.g., "255.255.255.0")
 * @return int CIDR prefix length (0-32) or -1 for invalid mask
 */
int mask_to_prefix_length(const char *mask) {
    /* 32-bit integer representation of subnet mask */
    uint32_t mask_num = 0;
    /* Array for storing mask octets */
    int parts[4];

    // Parse dotted decimal subnet mask
    /* Extract four octets from mask string */
    if (sscanf(mask, "%d.%d.%d.%d", &parts[0], &parts[1], &parts[2], &parts[3]) != 4) {
        return -1; // Invalid subnet mask
    }

    // Combine each part into 32-bit integer
    /* Convert octets to single 32-bit value */
    for (int i = 0; i < 4; i++) {
        /* Validate octet value range */
        if (parts[i] < 0 || parts[i] > 255) {
            return -1; // Invalid subnet mask part
        }
        mask_num = (mask_num << 8) | parts[i];
    }

    /* Initialize prefix length counter */
    int prefix_length = 0;

    // Calculate prefix length
    /* Count consecutive 1 bits from left */
    while (mask_num & 0x80000000) {
        prefix_length++;
        mask_num <<= 1;
    }

    fprintf("prefix_length:%d",prefix_length);
    // Check if mask has contiguous 1 bits
    //uint32_t check_mask = (1 << (32 - prefix_length)) - 1;

    /* Validate mask has contiguous 1 bits followed by 0 bits */
    if (mask_num != 0) {
        return -1; // Mask doesn't have contiguous 1 bits
    }

    return prefix_length;
}

/* 
 * Add route to system routing table and configuration file
 * This function performs both runtime and persistent route configuration
 * Converts subnet mask to CIDR notation for modern route commands
 * Validates mask format before attempting route addition
 * 
 * @param dev Network interface device name for route
 * @param dst Destination network address for route
 * @param mask Subnet mask in dotted decimal format
 * @return int Returns TRUE on success, FALSE on failure
 */
int add_route(const char *dev, const char *dst, const char *mask) {
    /* Buffer for constructing system command */
    char command[512];


    /* Buffer for CIDR prefix length string */
    char prefix_length_str[10];
    /* Convert subnet mask to prefix length */
    int prefix_length = mask_to_prefix_length(mask);
    /* Validate mask conversion was successful */
    if (prefix_length == -1) {
        fprintf(stderr, "Invalid subnet mask: %s\n", mask);
        return FALSE;
    }
    /* Convert prefix length to string */
    sprintf(prefix_length_str, "%d", prefix_length);

    /* Construct ip route add command */
    snprintf(command, sizeof(command), "ip route add %s/%s dev %s", dst, prefix_length_str, dev);
    /* Execute route command and update configuration file on success */
    if (execute_command(command) == 0) {
        add_route_to_file(dev, dst, prefix_length_str);
    } else {
        perror("Unable to add route");
        return FALSE;
    }
    return TRUE;
}

/* 
 * Clear all default routes from system routing table
 * This function removes all existing default gateway entries
 * Uses ip route show command to identify default routes
 * Executes individual deletion commands for each found route
 * 
 * @return int Returns 1 if all routes cleared successfully, 0 on any failure
 */
int clear_all_default_routes() {
    /* File pointer for command execution */
    FILE *fp;
    /* Buffer for reading command output */
    char line[256];

    /* Initialize return value to success */
    int ret = 1;
    /* Execute command to show default routes */
    fp = popen("ip route show | grep '^default'", "r");
    /* Validate command execution success */
    if (fp == NULL) {
        perror("Failed to run command");
        return 0;
    }

    /* Process each default route found */
    while (fgets(line, sizeof(line), fp) != NULL) {
        /* Buffer for route deletion command */
        char command[512];
        /* Construct route deletion command */
        snprintf(command, sizeof(command), "ip route del %s", line);
        /* Execute route deletion and check success */
        if (system(command) != 0) {
            perror("Unable to delete default route");
            ret = 0;
        }
    }

    /* Close command execution pipe */
    pclose(fp);
    /* Return overall operation status */
    return ret;

}

/* 
 * Add default route to system routing table
 * This function creates a default gateway entry with specified metric
 * Uses ip route command for immediate runtime configuration
 * Does not create persistent configuration in files
 * 
 * @param dev Network interface device name for default route
 * @param gateway Gateway IP address for default route
 * @param metric Route metric value for priority
 * @return int Returns TRUE on success, FALSE on failure
 */
int add_default_route(const char *dev, const char *gateway, const int metric) {
    /* Buffer for constructing system command */
    char command[512];
    /* Construct ip route add command for default route */
    snprintf(command, sizeof(command), "ip route add default via %s dev %s metric %d", gateway, dev, metric);
    
    /* Execute route command */
    if (execute_command(command) == 0) {
        //add_default_route_to_file(dev, gateway, metric);
    } else {
        perror("Unable to add default route");
        return FALSE;
    }
    return TRUE;
}

/* 
 * Delete route from system routing table and configuration file
 * This function removes both runtime and persistent route entries
 * Converts subnet mask to CIDR notation for route identification
 * Validates mask format before attempting route deletion
 * 
 * @param dev Network interface device name for route
 * @param dst Destination network address to remove
 * @param mask Subnet mask in dotted decimal format
 * @return int Returns TRUE on success, FALSE on failure
 */
int del_route(const char *dev, const char *dst, const char *mask) {
    /* Buffer for constructing system command */
    char command[512];

    /* Buffer for CIDR prefix length string */
    char prefix_length_str[10];
    /* Convert subnet mask to prefix length */
    int prefix_length = mask_to_prefix_length(mask);
    /* Validate mask conversion was successful */
    if (prefix_length == -1) {
        fprintf(stderr, "Invalid subnet mask: %s\n", mask);
        return FALSE;
    }
    /* Convert prefix length to string */
    sprintf(prefix_length_str, "%d", prefix_length);

    /* Construct ip route delete command */
    snprintf(command, sizeof(command), "ip route del %s/%s dev %s", dst, prefix_length_str, dev);
    /* Execute route command and update configuration file on success */
    if (execute_command(command) == 0) {
        delete_route_from_file(dev, dst, prefix_length_str);
    } else {
        perror("Unable to delete route");
    }
    return TRUE;
}

/* 
 * Modify existing route configuration
 * This function performs route modification by deletion and recreation
 * Used when route parameters need to be updated or changed
 * Not atomic - there may be a brief period without the route
 * 
 * @param dev Network interface device name for route
 * @param dst Destination network address for route
 * @param mask Subnet mask in dotted decimal format
 * @return int Result of route modification operation
 */
int mod_route(const char *dev, const char *dst, const char *mask) {
    /* Delete existing route */
    del_route(dev, dst, mask);
    /* Add new route with same parameters */
    add_route(dev, dst, mask);
}


/* 
 * Construct network configuration file path for specified device
 * This function generates the full file path for systemd network configuration
 * Handles special naming convention for PPP interfaces with prefix
 * Ensures consistent file path generation across different interface types
 * 
 * @param path Output buffer for file path (must be pre-allocated)
 * @param size Size of output buffer in bytes
 * @param dev Network interface device name
 * @return int Returns 0 on success
 */
int get_network_config_file_path(char *path, size_t size, const char *dev) {
    /* Check if device is PPP interface */
    if(strcmp(dev,"ppp0")==0 || strcmp(dev,"ppp1")==0){
        /* Generate PPP interface file path with prefix */
        snprintf(path, size, "/etc/systemd/network/%s%s.network", PPP_FILE_NAME_PERFIX,dev);
    }
    else{
        /* Generate standard interface file path */
        snprintf(path, size, "/etc/systemd/network/%s.network", dev);
    }
    return 0;
}

/* 
 * Check if specific route exists in network configuration file
 * This function scans network configuration file for matching route entries
 * Used to prevent duplicate route configurations and ensure idempotency
 * Performs exact string matching for route destination and prefix
 * 
 * @param file_path Path to network configuration file to check
 * @param dst Destination network address to verify
 * @param prefix_length_str CIDR prefix length as string
 * @return int Returns 1 if route exists, 0 if not found
 */
int check_route_exists(const char *file_path, const char *dst, const char *prefix_length_str) {
    /* Open configuration file for reading */
    FILE *file = fopen(file_path, "r");
    /* Validate file opened successfully */
    if (file == NULL) {
        perror("Failed to open network configuration file");
        return 0; //If file cannot open, route doesn't exist, continue add
    }

    /* Buffer for reading file lines */
    char line[256];
    /* Buffer for constructing expected route string */
    char expected_route[256];
    /* Format expected route configuration line */
    snprintf(expected_route, sizeof(expected_route),"Destination=%s/%s\n", dst, prefix_length_str);

    // Check for matching routes
    /* Scan each line in configuration file */
    while (fgets(line, sizeof(line), file)) {
        /* Compare current line with expected route */
        if (strcmp(line, expected_route) == 0) {
            fclose(file);
            return 1; // Find matching route and return 1
        }
    }

    fclose(file);
    return 0; // No matching route found and return 0
}

/* 
 * Remove default route configuration from network file
 * This function deletes default gateway entries from systemd network configuration
 * Parses file content to locate and remove [Route] sections with specific gateway
 * Maintains file structure by preserving other configuration sections
 * 
 * @param file_path Path to network configuration file to modify
 * @param gateway Gateway IP address to remove from configuration
 */
void Delete_default_route(const char *file_path, const char *gateway) {
    // Open file in read-only mode
    /* Open configuration file for reading */
    FILE *file = fopen(file_path, "r");
    /* Validate file opened successfully */
    if (!file) {
        perror("Delete_default_route fopen");
        return;
    }
    
    // Print debug information
    //printf("打开文件: %s\n", file_path);

    // Buffer for reading file lines
    char line[1024];
    // Dynamic array for storing file content
    // Dynamically allocate array for line storage
    char **lines = NULL;
    int line_count = 0;

    // Read each file line and store in lines array
    /* Process each line in configuration file */
    while (fgets(line, sizeof(line), file)) {
        // Remove trailing newline character
        line[strcspn(line, "\n")] = 0;
        
        // Dynamically expand array to store current line
        /* Reallocate memory for additional line */
        char **tmp = realloc(lines, (line_count + 1) * sizeof(char*));
        /* Validate memory allocation success */
        if (!tmp) { // Check reallocation success
            perror("realloc");
            /* Clean up previously allocated memory */
            for (int j = 0; j < line_count; j++) {
                free(lines[j]); // Free previous line memory
            }
            free(lines); // Free line array memory
            fclose(file);
            return;
        }
        lines = tmp; // Update pointer
        lines[line_count] = strdup(line); // Copy string
        /* Validate string duplication success */
        if (!lines[line_count]) { // Check strdup success
            perror("realloc");
            /* Clean up previously allocated memory */
            for (int j = 0; j < line_count; j++) {
                free(lines[j]); // Free previous line memory
            }
            free(lines); // Free line array memory
            fclose(file);
            return;
        }
        line_count++;
    }
    fclose(file); // Close file

    // Create new content excluding specified section
    /* Open file for writing new configuration */
    FILE *new_file = fopen(file_path, "w");
    /* Validate file opened successfully */
    if (!new_file) {
        perror("file_path fopen");
        // Free memory
        for (int i = 0; i < line_count; i++) {
            free(lines[i]);
        }
        free(lines);
        return;
    }

    int skip_section = 0; // Flag indicating whether to skip section
    /* Buffer for gateway match string */
    char gateway_str[64];
    /* Construct gateway match string */
    sprintf(gateway_str, "Gateway=%s", gateway); // Construct "gateway=数字" line

    /* Process each line for section filtering */
    for (int i = 0; i < line_count; i++) {
        // Check if specific section matches
        /* Identify default route section to delete */
        if (i < line_count - 2 && 
            strcmp(lines[i], "[Route]") == 0 && 
            strstr(lines[i + 1], gateway_str) != NULL && 
            strstr(lines[i + 2], "Metric=") != NULL) {
            skip_section = 1; // Activate skip flag
        }

        /* Handle section skipping logic */
        if (skip_section) {
            // Continue skipping section logic
            // printf("跳过段落: %s\n", lines[i]);
            // printf("跳过段落2: %s\n", lines[i+2]);
            i+=3;
        } else {
            // Write other lines to file
            fputs(lines[i], new_file);
            fputc('\n', new_file); // Add newline
        }
        skip_section = 0;
    }

    fclose(new_file); // Close new file
    // Free memory
    for (int i = 0; i < line_count; i++) {
        free(lines[i]); // Free line memory
    }
    free(lines); // Free line array memory
}

/* 
 * Create systemd network configuration file for specified interface
 * This function generates basic network configuration files for interfaces
 * Creates both .network and .netdev files with appropriate templates
 * Sets proper file permissions for systemd network management
 * 
 * @param param Interface name with file extension (.network or .netdev)
 */
void create_network_file(const char *param) {
    /* Buffer for file path construction */
    char filepath[BUFFER_SIZE];
    /* Buffer for new filename */
    char new_filename[BUFFER_SIZE];
    /* File pointer for file operations */
    FILE *file;

    // Check if file containing parameter string exists
    /* Directory pointer for file existence check */
    DIR *dir;
    /* Directory entry structure */
    struct dirent *entry;
    /* Flag for file existence */
    int file_exists = 0;

    /* Open network configuration directory */
    if ((dir = opendir(DIRECTORY)) == NULL) {
        perror("opendir");
        return;
    }

    /* Scan directory for existing files */
    while ((entry = readdir(dir)) != NULL) {
        /* Check if filename contains parameter string */
        if (strstr(entry->d_name, param) != NULL) {
            //printf("File %s already exists.\n", entry->d_name);
            file_exists = 1;
            break; // Stop searching after finding file
        }
    }
    closedir(dir);

    /* Return if file already exists */
    if (file_exists) {
        return; // If file exists, function ends
    }

    // Create new filename
    /* Construct full path for new network file */
    snprintf(new_filename, sizeof(new_filename), "%s%s%s", DIRECTORY,PPP_FILE_NAME_PERFIX, param);

    // Open file for writing
    /* Create and open new configuration file */
    file = fopen(new_filename, "w+");
    /* Validate file creation success */
    if (file == NULL) {
        perror("fopen");
        return;
    }

    // Select write content based on parameter suffix
    /* Determine file type and write appropriate template */
    if (strstr(param, ".network") != NULL) {
        /* Write .network file template with match section */
        fprintf(file, "[Match]\nName=%.*s\n\n[Network]\n\n",
                (int)(strlen(param) - 8), param);  // Remove suffix .network
    } else if (strstr(param, ".netdev") != NULL) {
        /* Write .netdev file template with netdev section */
        fprintf(file, "[NetDev]\nName=%.*s\n\n",
                (int)(strlen(param) - 7), param);  // Remove suffix .netdev
    } else {
        printf("Invalid parameter. Must end with .network or .netdev.\n");
        fclose(file);
        return;
    }
    
    // Close file
    fclose(file);

    // Set file permissions to 744
    /* Apply read permissions for all, write/execute for owner only */
    if (chmod(new_filename, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR) < 0) {
        perror("chmod");
        return;
    }

    printf("File %s created with permissions 744.\n", new_filename);
}

/* 
 * Create PPP interface network configuration files
 * This function generates all required systemd network files for PPP interfaces
 * Creates both ppp0 and ppp1 configuration with proper file naming
 * Ensures PPP interfaces are properly configured for network management
 */
void creat_PPP_network_file(void){
    /* Create ppp0 network configuration file */
    create_network_file("ppp0.network");
    /* Create ppp0 netdev configuration file */
    create_network_file("ppp0.netdev");
    /* Create ppp1 network configuration file */
    create_network_file("ppp1.network");
    /* Create ppp1 netdev configuration file */
    create_network_file("ppp1.netdev");
}

/* 
 * Execute shell command and return result
 * This function provides a wrapper for system command execution
 * Used for various route management and network configuration commands
 * Returns the exit status of the executed command
 * 
 * @param command Shell command string to execute
 * @return int Exit status of the executed command
 */
int execute_command(const char *command) {
    return system(command);
}

/* 
 * Set default route based on active network interfaces
 * This function analyzes current routing table to determine active interfaces
 * Creates default routes with priority based on interface type and availability
 * Uses predefined metric values for different interface types (PPP vs Ethernet)
 * 
 * Buffer size definition for command output processing
 */
#define BUFFER_SIZE 1024
void set_default_route_info(void) {
    // Create pipe for command execution
    /* File pointer for command output */
    FILE *fp;
    /* Buffer for reading command output */
    char buffer[BUFFER_SIZE];
    /* Buffer for constructing route commands */
    char command[BUFFER_SIZE>>1] = {0};
    // Store command output result
    /* Allocate memory for result string */
    char *result = malloc(BUFFER_SIZE);
    /* Validate memory allocation success */
    if (!result) {
        perror("Unable to allocate memory");
        return NULL;
    }
    result[0] = '\0'; // Initialize result string

    // Run route -n command
    /* Execute route command to get routing table */
    fp = popen("route -n", "r");
    /* Validate command execution success */
    if (fp == NULL) {
        perror("Failed to run command");
        free(result);
        return NULL;
    }

    // Skip first two header lines
    fgets(buffer, sizeof(buffer), fp); // Skip "Kernel IP routing table" line
    fgets(buffer, sizeof(buffer), fp); // Skip column title line

    // Read each line and extract Iface column
    /* Process each route table entry */
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        /* Extract destination column first */
        char *iface = strtok(buffer, " \t"); // Get Destination column
        /* Skip gateway and genmask columns */
        for (int i = 0; i < 3; i++) {
            iface = strtok(NULL, " \t"); // Skip other columns
        }
        /* Validate interface name extraction */
        if (iface != NULL) {
            // Add Iface to result string with space separator
            strcat(result, iface);
            strcat(result, " ");
        }
    }

    // Close pipe
    pclose(fp);

    printf("result=%s\n",result);
    // Remove trailing space
    size_t len = strlen(result);
    if (len > 0) {
        result[len - 1] = '\0'; // Replace trailing space with string terminator
    }
     
    /* Clear command buffer for new construction */
    memset(command,0,sizeof(command));
    /* Check for ppp0 interface in results */
    if(strstr(result,"ppp0") != NULL)
    {
        /* Create default route for ppp0 with metric 101 */
        snprintf(command, sizeof(command), "ip route add default via 0.0.0.0 metric 101 dev ppp0");
    }
    /* Check for ppp1 interface in results */
    else if(strstr(result,"ppp1") != NULL)
    {
        /* Create default route for ppp1 with metric 102 */
        snprintf(command, sizeof(command), "ip route add default via 0.0.0.0 metric 102 dev ppp1");
    }
    /* Check for eth1 interface in results */
    else if(strstr(result,"eth1") != NULL)
    {
        /* Create default route for eth1 with metric 103 */
        snprintf(command, sizeof(command), "ip route add default via 0.0.0.0 metric 103 dev eth1");
    }
    /* Execute route command if interface found */
    if(strlen(command) > 1)
    {
        /* Add default route to system */
        if (execute_command(command) == 0) 
        {
            printf("add default route successful\n");
        } else 
        {
            perror("add route error");
        }
    }
}